package com.grace.cms.forum.user.security.config;
import static org.springframework.security.config.Customizer.withDefaults;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.grace.cms.forum.user.filter.WebJwtAuthenticationTokenFilter;
import com.grace.cms.forum.user.security.CustomAuthenticationDetailsSource;
import com.grace.cms.forum.user.security.CustomAuthenticationProvider;
import com.grace.cms.forum.user.security.hand.MyAuthenticationFailureHandler;
import com.grace.cms.forum.user.security.hand.MyAuthenticationSuccessHandler;
import com.grace.cms.forum.user.security.hand.MyLogoutSuccessHandler;
import com.grace.cms.forum.user.security.hand.WebAuthenticationEntryPointImpl;
import com.grace.cms.forum.user.security.service.RedisTokenRepositoryImpl;
import com.grace.cms.forum.user.security.service.WebUserDetailsService;
import com.grace.cms.common.constant.OlySystemConstant;

/**
 * spring security配置
 * 
 * @author grace
 */
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
public class WebSecurityConfig {

        /**
         * 自定义用户认证逻辑
         */
        @Autowired
        private WebUserDetailsService userDetailsService;


        @Autowired
        private WebJwtAuthenticationTokenFilter webJwtAuthenticationTokenFilter;

        @Autowired
        private CustomAuthenticationDetailsSource authenticationDetailsSource;

        @Autowired
        private MyAuthenticationFailureHandler failureHandler;

        @Autowired
        private MyAuthenticationSuccessHandler successHandler;

        @Autowired
        private MyLogoutSuccessHandler logoutOutHandler;

        @Autowired
        private RedisTokenRepositoryImpl repository;

        /**
         * 配置HTTP安全设置，定义Spring Security的访问规则和行为。
         * 
         * @param http 用于配置HttpSecurity的接口，可定制应用程序的请求处理方式，例如认证、授权、CSRF保护等。
         * @throws Exception 如果配置过程中发生错误，则抛出异常。
         */
        @Bean
        protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {

                return httpSecurity.csrf(csrf -> csrf.disable())
                                // 添加认证异常入口
                                .exceptionHandling(handling -> handling
                                                .authenticationEntryPoint(new WebAuthenticationEntryPointImpl()))
                                .authorizeHttpRequests(requests -> requests
                                                // 允许匿名访问
                                                .requestMatchers(HttpMethod.GET, "/**", "/*" +
                                                                OlySystemConstant.MANAGE_URL_PREFIX + "/**",
                                                                "/*/static/**", "/*/register","/druid/**",
                                                                "/*/api/**")
                                                .permitAll()
                                                // 允许匿名访问
                                                .requestMatchers(HttpMethod.POST, "/*" +
                                                                OlySystemConstant.MANAGE_URL_PREFIX + "/**",
                                                                "/*/general/record/*/addLookRecord",
                                                                "/*/doRegister", "/*/general/**","/druid/**",
                                                                "/*/user/**")
                                                .permitAll()
                                                // 需要认证
                                                .requestMatchers(HttpMethod.POST, "/*/hand/**", "/*/user/**")
                                                .authenticated()
                                                .anyRequest().authenticated())
                                .formLogin(login -> login
                                                // loginPage 登录页面 loginProcessingUrl 登录处理
                                                .loginPage("/*/login").permitAll().loginProcessingUrl("/*/doLogin")
                                                .permitAll().successHandler(successHandler)
                                                .failureHandler(failureHandler)
                                                .authenticationDetailsSource(authenticationDetailsSource))
                                // 启用记住密码
                                .authorizeHttpRequests(withDefaults())
                                .rememberMe(me -> me.tokenValiditySeconds(5 * 24 * 60 * 60).tokenRepository(repository)
                                .userDetailsService(userDetailsService))
                                .logout(logout -> logout.logoutUrl("/*/logout").logoutSuccessHandler(logoutOutHandler))
                                // 添加JWT filter
                                .addFilterBefore(webJwtAuthenticationTokenFilter,
                                                UsernamePasswordAuthenticationFilter.class)
                                // .addFilterBefore(customAuthenticationFilter(),
                                // UsernamePasswordAuthenticationFilter.class)
                                .build();
        }

        /**
         * 强散列哈希加密实现
         */
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
                return new BCryptPasswordEncoder();
        }

        /**
         * 身份验证实现
         */
        // @Bean
        // public AuthenticationManager authenticationManager() {
        // DaoAuthenticationProvider daoAuthenticationProvider = new
        // DaoAuthenticationProvider();
        // daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        // daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
        // daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
        // return new ProviderManager(daoAuthenticationProvider);
        // }

        @Bean
        public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
                return authConfig.getAuthenticationManager();
        }

        @Bean
        public CustomAuthenticationProvider authenticationProvider() {
                CustomAuthenticationProvider customAuthenticationProvider = new CustomAuthenticationProvider(userDetailsService);
                customAuthenticationProvider.setHideUserNotFoundExceptions(true);
                return customAuthenticationProvider;
        }    

}
